
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#include "soc.h"
#include "dw_i2c.h"
#include "dbg_cli.h"
#include "upaket.h"
#include "umsg.h"



/*
    debug bridge spi 是个 6 pin 接口,  cs, clk, dat[3:0];
    在 milkv-duo 开发板上, 选择 SPI-NOR-NAND 对应的 6 pin 接口;
   
    PAD     XGPIOA    SPI-NOR      milkv-duo
    17      26        HOLD#        GP21
    18      22        SCK          GP18
    19      25        MOSI         GP19
    20      27        WP#          GP20
    21      23        MISO         GP16
    22      24        CS#          GP17

    
    对于芯片的 PAD MUX 和 PAD control 的寄存器是按照 PAD 位置来定义.
*/

void qspi_pad_config( void )
{

	/* SPI-NOR, */
	write_reg( PAD_MUX_17, 1 );
	write_reg( PAD_MUX_18, 1 );
	write_reg( PAD_MUX_19, 1 );
	write_reg( PAD_MUX_20, 1 );
	write_reg( PAD_MUX_21, 1 );
	write_reg( PAD_MUX_22, 1 );

	/* IIC-0 */
	write_reg( PAD_MUX_23, 4 );
	write_reg( PAD_MUX_24, 4 );

	// [11] 输出电平转换速率限制. 0=无效(较快) ; 1=有效(较慢)
	// [8] 输入施密特触发强度?
	// [7:5] 输出驱动能力.
    // [3] 下拉电阻, 0=无效; 1=有效
    // [2] 上拉电阻, 0=无效; 1=有效

	// PAD_CTL_17
	// PAD_CTL_18
	// PAD_CTL_19
	// PAD_CTL_20
	// PAD_CTL_21
	// PAD_CTL_22

	// LED,  PAD-1, GPIOC-24
	write_reg( PAD_MUX_1, 3 );
}



int test_read( cvi_spinor_regs_t * psnor, uint16_t addr, int tcnt, uint32_t * pdat )
{
	uint32_t temp;
	uint32_t ffss;
	uint32_t ints;
	uint32_t tagh;
	int offs;
	
	if ( tcnt <= 1 )  {
		tcnt = 1;
	}

	// 1 : Read
	tagh = 0x10000 | addr;
	tagh = ( tagh << 7 ) | ( (tcnt - 1) & 0x7F );

	/* clear irqs and fifo */
	psnor->FIFO_PT = 0;
	psnor->CE_CTRL = 0;
	psnor->INT_STS = 0;

	/* trans multi words */
	psnor->TRAN_NUM = tcnt << 2;

	/* RX, addr(3) ,  ff_trg_lvl = 4bytes */
	temp = 0x2301;
	psnor->TRAN_CSR = temp;

	/* push addr : 24 bits */
	psnor->FF32 = __builtin_bswap32( tagh );
	ffss = psnor->FF8;

	psnor->TRAN_CSR = temp | 0x8000;
	
	/* check RD fifo int */
	while ( true )  {

		ints = psnor->INT_STS;
		psnor->INT_STS = 0;

		if ( ints & 0x4 )  {
			break;
		}
	}

	offs = 0;
	while ( true )  {

		ffss = psnor->FIFO_PT;
		if ( (ffss & 0xF) >= 4 )  {
			pdat[offs] = __builtin_bswap32( psnor->FF32 );
			offs += 1;
		}

		ints = psnor->INT_STS;

		if ( ints & 0x1 )  {
			break;
		}
	}

	// printf( "offs = %d\n", offs );
	return 0;
}


/*
tcnt : 表示后面 pdat 数组的长度, <=0 都没有意义.  最大值 128.
*/
int test_write( cvi_spinor_regs_t * psnor, uint16_t addr, int tcnt, uint32_t * pdat )
{
	uint32_t temp;
	uint32_t ffss;
	uint32_t ints;	
	volatile uint32_t tagh;
	int offs;

	if ( (tcnt < 1) || (tcnt > 128) )  {
		return 123;
	}

	// 0 : Write
	tagh = addr;
	tagh = ( tagh << 7 ) | ( (tcnt - 1) & 0x7F );

	/* clear irqs and fifo */
	psnor->FIFO_PT = 0;
	psnor->CE_CTRL = 0;
	psnor->INT_STS = 0;

	/* trans multi words */
	psnor->TRAN_NUM = tcnt << 2;

	/* RX, cmd + addr(2) ,  ff_trg_lvl = 4bytes */
	temp = 0x2302;
	psnor->TRAN_CSR = temp;

	/* push addr : 24 bits */
	psnor->FF32 = __builtin_bswap32( tagh );
	ffss = psnor->FF8;
	
	/**/
	psnor->TRAN_CSR = temp | 0x8000;

	/* check WR fifo int */
	while ( true )  {

		ints = psnor->INT_STS;
		psnor->INT_STS = 0;

		if ( ints & 0x8 )  {
			break;
		}
	}

	/* push all data */
	offs = 0;
	while ( true )  {

		ffss = psnor->FIFO_PT;
		if ( (ffss & 0xF) <= 4 )  {
			psnor->FF32 = __builtin_bswap32( pdat[offs] );
			offs += 1;
		}

		if ( offs == tcnt ) {
			break;
		}
	}

	/* wait complete */
	while ( true )  {
		ints = psnor->INT_STS;

		if ( ints & 0x1 )  {
			break;
		}
	}

	return 0;
}


/*
fifo 最大深度 8 bytes.
会根据 write 操作的的 mask 来 push 数据.
如果 word 写操作, 那么 push 4 bytes.
但是 byte 写操作, 只会 push 1 byte.

怀疑, 硬件不认识 half (uint16) 写操作.
*/

int bl2_dbg_nor( void * pctx, int argc, const char * argv[] )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;

	/* default setting .*/
	psnor->DMMR_CTRL = 0;			/* disable */
	psnor->SPI_CTRL = 0x8001D;		/* div = 2 * (0x1D + 1) = 60, 300Mhz / 60 = 5Mhz  */
	psnor->INT_STS = 0;
	psnor->FIFO_PT = 0;				/* clear fifo */
	psnor->CE_CTRL = 0;

	return 0;
}



int bl2_dbg_info( void * pctx, int argc, const char * argv[] )
{
	uint64_t temp;

	temp = csr_read( mapbaddr );

	printf( "mapbaddr = %x, %x\n",  (uint32_t)(temp >> 32),  (uint32_t)temp );
	return 0;
}



/*
关闭 data cache
*/
int bl2_dbg_cache( void * pctx, int argc, const char * argv[] )
{
	uint64_t temp;
	
	/**/
	__DCACHE_CIALL();
	__DSB();

	temp = __get_MHCR();
	__set_MHCR( temp & 0xFFD );
	
	printf( "mhcr org = %x\n", (uint32_t)temp );
	return 0;
}





extern int bl2_dbg_usb_init( void * pctx, int argc, const char * argv[] );



int log_init( int tsiz );
int log_flush( void );


int bl2_dbg_logcat( void * pctx, int argc, const char * argv[] )
{
	log_flush();
	return 0;
}


int bl2_dbg_rtscore( void * pctx, int argc, const char * argv[] )
{
	uint32_t temp;
	uint32_t tsiz;

	// check : 0x0E000040, 0x0E000044, 0x0E00004C .
	temp = read_reg( 0x0E00004C );
	if ( temp != 0x87654321 )  {
		return 123;
	}

	// memcpy
	temp = read_reg( 0x0E000040 );
	tsiz = read_reg( 0x0E000044 );
	memcpy( (void *)(intptr_t)0x3BC00000, (void *)(intptr_t)temp, (size_t)tsiz );

	// SEC_SUBSYS_BASE
	write_reg( 0x020B0004, 0x2000 );
	write_reg( 0x020B0020, 0x3BC00000 );
	write_reg( 0x020B0024, 0 );
	
	/**/
	__DCACHE_CIALL();
	__DSB();

	// 
	temp = read_reg( 0x03003024 );
	temp = temp | 0x40;
	write_reg( 0x03003024, temp );
	return 0;
}



int test_ecall( uint32_t esno, intptr_t arg0, intptr_t arg1, intptr_t arg2 )
{
    register uintptr_t a7 asm("a7") = (uintptr_t)esno;
    register intptr_t a0 asm("a0") = arg0;
    register intptr_t a1 asm("a1") = arg1;
    register intptr_t a2 asm("a2") = arg2;
	    
    asm volatile("ecall"
                : "+r"(a0)
                : "r"(a1), "r"(a2), "r"(a7)
                : "memory");
	return a0;
}


void  umsg_send_to_host( umsg_t * pmsg )
{
	// pack rqc
	pmsg->data[0] = (uint8_t)pmsg->rqc;
	pmsg->data[1] = (uint8_t)( pmsg->rqc >> 8 );

	test_ecall( 123, (intptr_t)(pmsg->data), pmsg->offs, 0 );
}


void * umsg_alloc_for_user( void )
{
	int iret;
	
	iret = test_ecall( 134, 0, 0, 0 );
	return (void *)(intptr_t)iret;
}


/*
uint16_t  reqc;	// 
*/


#define  RQC_SPI_READ		0x0011
#define  RQC_SPI_WRITE		0x0012

#define  RQC_DDR_READ		0x0202
#define  RQC_DDR_WRITE		0x0207

#define  RQC_ADI_READ		0x0101
#define  RQC_ADI_WRITE		0x0102

#define  RQC_CVB_READ		0x0702
#define  RQC_CVB_WRITE		0x0707

#define  RQC_IIC_CONFIG		0xFF08			// SI5324, PLL-CONFIG
#define  RQC_SYS_RESET		0xFF10
#define  RQC_SYS_DEBUG		0xFF20


/*
输入的 msg 谁来释放?

如果返回 0 , 那么此函数已经回馈了 msg 给 host .

如果其他错误码? 需要总体框架通过错误机制来记录或上报.
*/
int proc_spi_read( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int iret;
	uint16_t addr;
	uint8_t cntw;
	uint32_t  tary[128];

	iret = umsg_remains( pmsg );
	if ( iret < 3 )  {
		return 1234;
	}

	addr = umsg_get_u16( pmsg );
	cntw = umsg_get_u8( pmsg );

	iret = test_read( psnor, addr, (int)cntw, tary );
	if ( iret != 0 )  {
		return 100 + iret;
	}

	// pack data to umsg.
	umsg_reset_ofs( pmsg );
	
	for ( int i=0; i<(int)cntw; i++ )  {
		umsg_add_u32( pmsg, tary[i] );
	}

	umsg_send_to_host( pmsg );
	return 0;
}


int proc_spi_write( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int iret;
	int cntw;
	uint16_t addr;
	uint32_t  tary[128];

	// 
	cntw = umsg_remains( pmsg );
	if ( cntw < 6 )  {
		return 2345;
	}

	addr = umsg_get_u16( pmsg );
	cntw = ( cntw - 2 ) / sizeof(uint32_t);

	for ( int i=0; i<cntw; i++ )  {
		tary[i] = umsg_get_u32( pmsg );
	}

	printf( "spi, write, %d\n", cntw );

	iret = test_write( psnor, addr, cntw, tary );
	if ( iret != 0 )  {
		return 100 + iret;
	}

	// pack data to umsg.
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}


/*
2 字节的 RQC 之后.
是个 reg addr 数组,  数组的成员都是 byte 大小.

0x300 : 
  [31] : 0 表示操作完成.
  [15] : 0-write, 1-read.
[14:8] : ad9685, reg addr.
 [7:0] : ad9685, reg data.
*/
int proc_adi_read( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int cntw;
	uint8_t tary[20];
	uint32_t temp;
	uint64_t told;
	uint64_t tnew;


	//
	cntw = umsg_remains( pmsg );
	for ( int i=0; i<cntw; i++ ) {
		tary[i]	= umsg_get_u8( pmsg );
		printf( "adi read idx : %x\n", tary[i] );
	}

	// 
	umsg_reset_ofs( pmsg );

	for ( int i=0; i<cntw; i++ ) {

		temp = 0x80 | tary[i];
		temp = temp << 8;
		test_write( psnor, 0x300, 1, &temp );

		told = __get_MTIME();

		while ( true ) {
			test_read( psnor, 0x300, 1, &temp );

			if ( (temp & 0x80000000) == 0 )  {
				break;
			}

			// check timeout
			tnew = __get_MTIME();
			if ( (tnew - told) >= 2500000 )  {

				umsg_reset_ofs( pmsg );
				umsg_add_i32( pmsg, 0x45678 );
				umsg_send_to_host( pmsg );
				return 0;
			}
		}

		//
		printf( "300: %x\n", temp );
		umsg_add_u8( pmsg, (uint8_t)(temp & 0xff) );
	}
	
	umsg_send_to_host( pmsg );
	return 0;
}


int proc_adi_write( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int cntw;
	uint16_t tary[20];
	uint32_t temp;

	//
	cntw = umsg_remains( pmsg );
	for ( int i=0; i<cntw; i+=2 ) {
		tary[i]	= umsg_get_u8( pmsg );
		tary[i]	= (tary[i] << 8) | umsg_get_u8( pmsg );
		printf( "idx : %x\n", tary[i] );
	}

	// 
	cntw = cntw / 2;
	for ( int i=0; i<cntw; i++ ) {

		temp = tary[i];
		test_write( psnor, 0x300, 1, &temp );

		while ( true ) {
			test_read( psnor, 0x300, 1, &temp );

			if ( (temp & 0x80000000) == 0 )  {
				break;
			}
		}

		//
		printf( "300: %x\n", temp );
	}
	
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}


int SI5324_ReadReg( uint32_t address, uint8_t RegAdr, uint8_t * pval )
{
	uint32_t temp;
	dw_iic_regs_t * piic = (dw_iic_regs_t *)0x04000000;
	
    /**/
    dw_iic_set_target_address( piic, address );
    dw_iic_clear_all_irq( piic );
    dw_iic_enable( piic );

    /* write address */
    piic->IC_DATA_CMD = RegAdr;
	
    /* wait */
    while ( 1 ) {
        if ( piic->IC_RAW_INTR_STAT & DW_IIC_RAW_TX_ABRT ) {
            break;
        }

        if ( piic->IC_TXFLR == 0 ) {
            break;
        }
    }
    
    if ( piic->IC_RAW_INTR_STAT & DW_IIC_RAW_TX_ABRT ) {
        temp = piic->IC_TX_ABRT_SOURCE;
        printf( "tx fail, %08x\n", temp );

        /**/
        dw_iic_disable( piic );
        return (int)__LINE__;
    }

    /* restart, read + stop */
    piic->IC_DATA_CMD = 0x700;
    
    /* wait */
    while ( 1 ) {
        if ( piic->IC_RXFLR == 1 ) {
            break;
        }
    }
    
    /**/
    *pval = (uint8_t)( piic->IC_DATA_CMD );

    /* finish, deinit */
    dw_iic_disable( piic );    
	return 0;
}



/// @brief SI5324写寄存器
/// @param address 外设地址
/// @param RegAdr  写的寄存器地址
/// @param value 写的值
int SI5324_WriteReg( uint32_t address, uint8_t RegAdr, uint8_t value)
{
    uint32_t temp;
	dw_iic_regs_t * piic = (dw_iic_regs_t *)0x04000000;
	
    /**/
    dw_iic_set_target_address( piic, address );
    dw_iic_clear_all_irq( piic );
    dw_iic_enable( piic );
    
    /* write */
    piic->IC_DATA_CMD = RegAdr;
	piic->IC_DATA_CMD = (0x2<<8)|value;
    

    /* wait */
    while ( 1 ) {
        if ( piic->IC_RAW_INTR_STAT & DW_IIC_RAW_TX_ABRT ) {
            break;
        }

        if ( piic->IC_TXFLR == 0 ) {
            break;
        }
    }
    
    if ( piic->IC_RAW_INTR_STAT & DW_IIC_RAW_TX_ABRT ) {
        temp = piic->IC_TX_ABRT_SOURCE;
        printf( "tx fail, %08x\n", temp );

        /**/
        dw_iic_disable( piic );
        return (int)__LINE__;
    }

    /* finish, deinit */
    dw_iic_disable( piic );
    return 0;
}


int proc_iic_config( umsg_t * pmsg )
{
	int iret;
	int cntw;
	uint8_t addr[64];
	uint8_t vals[64];

	//
	cntw = umsg_remains( pmsg );
	cntw = cntw / 2;

	for ( int i=0; i<cntw; i++ ) {
		addr[i]	= umsg_get_u8( pmsg );
		vals[i]	= umsg_get_u8( pmsg );
		printf( "idx : %x\n", addr[i] );
	}

	//
	for ( int i=0; i<cntw; i++ ) {
		iret = SI5324_WriteReg( 0x68, addr[i], vals[i] );
		if ( iret != 0 )  {
			return (int)__LINE__;
		}
	}

	/* 0 表示成功. */
	umsg_reset_ofs( pmsg );
	umsg_add_i32( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}



static uint8_t si5324_dft_cfg[43][2] = {
	{ 0, 0x54 	},
	{ 1, 0xE4	},
	{ 2, 0x12	},
	{ 3, 0x15	},
	{ 4, 0x92	},
	{ 5, 0xED	},
	{ 6, 0x2D	},
	{ 7, 0x2A	},
	{ 8, 0x00	},
	{ 9, 0xC0	},
	{ 10, 0x00	},
	{ 11, 0x40	},
	{ 19, 0x29	},
	{ 20, 0x3E	},
	{ 21, 0xFF	},
	{ 22, 0xDF	},
	{ 23, 0x1F	},
	{ 24, 0x3F	},
	{ 25, 0x60	},
	{ 31, 0x00	},
	{ 32, 0x00	},
	{ 33, 0x03	},
	{ 34, 0x00	},
	{ 35, 0x00	},
	{ 36, 0x1F	},
	{ 40, 0xC3	},
	{ 41, 0x34	},
	{ 42, 0x4F	},
	{ 43, 0x00	},
	{ 44, 0x1C	},
	{ 45, 0x79	},
	{ 46, 0x00	},
	{ 47, 0xA7	},		// check for config.
	{ 48, 0x68	},		// check for config.
	{ 55, 0x00	},
	{ 131, 0x1F },
	{ 132, 0x02	},
	{ 137, 0x01	},
	{ 138, 0x0F	},
	{ 139, 0xFF	},
	{ 142, 0x00	},
	{ 143, 0x00	},
	{ 136, 0x40	},
};



int bl2_si5324_try_config( dw_iic_regs_t * piic )
{
	int iret;

	/**/


	for ( int i=0; i<43; i++ )  {
		iret = SI5324_WriteReg( 0x68, si5324_dft_cfg[i][0], si5324_dft_cfg[i][1] );
		if ( iret != 0 )  {
			return 124;
		}
	}

	return 0;
}


int bl2_iic_init( dw_iic_regs_t * piic, uint32_t baud )
{
    /**/
    dw_iic_init( piic, baud );
    dw_iic_set_master_mode( piic );
    dw_iic_set_transfer_speed_fast( piic );
	return 0;
}



/*
tsiz 是请求要读的 word 个数, 但是此函数一次最多 127 个 word.
返回实际 读出来的 word 个数.
*/
int part_read( cvi_spinor_regs_t * psnor, uint16_t offs, uint32_t tsiz, uint32_t * pary )
{
	int iret;

	if ( tsiz > 127 )  {
		tsiz = 127;
	}

	iret = test_read( psnor, (offs + 0x1000), tsiz, pary );
	if ( iret != 0 )  {
		return -200;
	}

	//
	return tsiz;
}



/*
input : 
	uint16  rqc;	// 
	uint32  addr;	// 地址需要 4 字节对齐.
	uint32  size;	// 表示要读出来的 word 数量.

output:
	uint16  rqc;
	uint16  sno;			// 第一个 pakcet, sno = 0,  随后每个 packet 中 sno 递增, 表示已经传输的 word 个数.
	uint32  array[127];		// 每次最多 127 个 word , 因为 usb 最大 packet 是 512 字节.

在 cv1800b 上,  一次 input 请求, 导致持续的循环上送.
如果第一个上送的 sno 不是 0 ,  表示错误码.
如果后续 sno 不连续, 也可以用来表示错误码.
*/

// umsg_alloc_for_user

int proc_mem_read( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int iret;
	int cntw;
	uint32_t addr;
	uint32_t tsiz;
	uint32_t offs;

	cntw = umsg_remains( pmsg );
	if ( cntw < 4 )  {
		goto errport;
	}

	addr = umsg_get_u32( pmsg );
	tsiz = umsg_get_u32( pmsg );

	// 第一个响应报文不含 mem 内容, 仅仅表示正常.
	umsg_reset_ofs( pmsg );
	umsg_add_u16( pmsg, 0 );
	umsg_send_to_host( pmsg );


	// 开始循环上送 packet,  每个 packet 包含 127 个 word.
	offs = 0;

	while ( true )  {

		uint32_t winbp;
		int temp;

		/* 申请一个新的 pmsg */
		pmsg->data = (uint8_t *)umsg_alloc_for_user();
		if ( pmsg->data == NULL )  {
			printf( "error : mem read loop, alloc pmsg NULL\n" );
			return 111;
		}

		// pmsg->rqc = RQC_MEM_READ;
		umsg_reset_ofs( pmsg );
		umsg_add_u16( pmsg, (uint16_t)offs );

		/* write WinBase : reg[0]
		 * 需要 floor 到 12 bit 边界地址.
		 * 因为第一个 packet, 不用考虑历史值, 直接设置.
		 */
		winbp = (addr + (offs << 2)) & 0xFFFFF000;
		test_write( psnor, 0, 1, &winbp );

		/* 计算这次读取的 word 个数, 最多 127. */
		temp = (int)( tsiz - offs );
		if ( temp > 127 ) {
			temp = 127;
		}

		iret = test_read( psnor, (addr + (offs << 2) - winbp) + 0x1000, temp, (uint32_t *)(pmsg->data + 4) );
		if ( iret != 0 )  {
			return -200;
		}
		
		//
		umsg_skip( pmsg, temp * 4 );
		umsg_send_to_host( pmsg );
		
		//
		offs += temp;
		if ( offs >= tsiz )  {
			break;
		}
	}
	
	// todo : 是否最后上送一个 特殊消息?
	return 0;

errport:

	/* 非 0 表示错误码. */
	umsg_reset_ofs( pmsg );
	umsg_add_u16( pmsg, 0x1234 );
	umsg_send_to_host( pmsg );
	return 0;
}


/*
input :
	uint16  rqc;	// 
	uint32  addr;	// 地址需要 4 字节对齐.
	uint32  array[126];		// 每次最多 126 个 word , 因为 usb 最大 packet 是 512 字节.

output :
	uint16  rqc;	// 
	uint16  errcode;
*/

int proc_mem_write( umsg_t * pmsg )
{
	cvi_spinor_regs_t * psnor = (cvi_spinor_regs_t *)SPINOR_BASE;
	int cntw;
	uint32_t addr;
	uint32_t winbp;
	uint32_t tary[128];

	cntw = umsg_remains( pmsg );
	if ( cntw < 8 )  {
		goto errport;
	}

	addr = umsg_get_u32( pmsg );
	cntw = (cntw / 4) - 1;

	for ( int i=0; i<cntw; i++ )  {
		tary[i] = umsg_get_u32( pmsg );
	}

	// write winbp:
	winbp = addr & 0xFFFFF000;
	test_write( psnor, 0, 1, &winbp );

	addr = (addr - winbp) + 0x1000;
	test_write( psnor, addr, cntw, tary );

	// printf( "mem : %x, %x, %u\n", winbp, addr, cntw );
	// debug_dump_hex( (uint8_t *)tary, 32 );
	
	//
	umsg_reset_ofs( pmsg );
	umsg_add_u16( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;

errport:
	/* 非 0 表示成功. */
	umsg_reset_ofs( pmsg );
	umsg_add_u16( pmsg, 0x1234 );
	umsg_send_to_host( pmsg );
	return 0;
}



int proc_sys_debug( umsg_t * pmsg )
{
	log_flush();

	/**/
	umsg_reset_ofs( pmsg );
	umsg_add_u16( pmsg, 0 );
	umsg_send_to_host( pmsg );
	return 0;
}



/* GPIOC-24 */
void led_init( cvi_gpio_regs_t * pgpio )
{
	uint32_t temp;
	
	temp = pgpio->OPE;
	temp = temp | 0x1000000;
	pgpio->OPE = temp;

	return;
}


void led_toggle( cvi_gpio_regs_t * pgpio, uint32_t period )
{
	static uint64_t tick_old;
	uint64_t tick;
	uint64_t iterv;
	uint32_t temp;
	
	/* mtime, 25Mhz?  */
	tick = __get_MTIME();
	iterv = tick - tick_old;
	iterv = iterv / 25000;
	if ( iterv < period )  {
		return;
	}

	/**/
	tick_old = tick;
	temp = pgpio->OUT;
	temp = temp ^ 0x1000000;
	pgpio->OUT = temp;
	return;
}





int main( void )
{
	int iret;
	cvi_gpio_regs_t * pgpio = (cvi_gpio_regs_t *)CVI_GPIOC_BASE;
	int tlen;
	void * ptr;
	umsg_t tmsg;

	/**/
	qspi_pad_config();
	led_init( pgpio );
	log_init( 16000 );

	/*  iic, SI5324, try config. */
	dw_iic_regs_t * piic = (dw_iic_regs_t *)0x04000000;
	bl2_iic_init( piic, 300000 );
	// iret = bl2_si5324_try_config( piic );
	// printf( "si5324 config = %d\n", iret );

	/* dbg-spi */
	bl2_dbg_nor( NULL, 0, NULL );

	/* packet memory pool ...*/
	iret = upk_init();
	printf( "upk pool init = %d\n", iret );

	// global MIE.
	__enable_irq();
	bl2_dbg_usb_init( NULL, 0, NULL );
	test_sleep( 100000 );

	
	/**/
	while ( true )  {
	
		// __disable_irq();
		iret = upk_recv_from_dev( &ptr, &tlen );
		// __enable_irq();

		if ( iret != 0 )  {
			//
			led_toggle( pgpio, 500 );
			// __WFI();
			__NOP();
			__NOP();
			continue;
		}

		if ( tlen < 2 )  {
			/* dump */
			debug_dump_hex( ptr, tlen );
			continue;
		}

		/* special, system reset */
		tmsg.rqc = *(uint16_t *)ptr;
		if ( tmsg.rqc == RQC_SYS_RESET )  {
			break;
		}

		tmsg.data = (uint8_t *)ptr;
		tmsg.offs = 2;
		tmsg.mlen = tlen;

		// printf( "bff %x\n", tmsg.rqc );

		switch ( tmsg.rqc )  {

		case RQC_SPI_READ:
			iret = proc_spi_read( &tmsg );
			break;

		case RQC_SPI_WRITE:
			iret = proc_spi_write( &tmsg );
			break;

		case RQC_DDR_WRITE:
			iret = proc_mem_write( &tmsg );
			break;
			
		case RQC_DDR_READ:
			iret = proc_mem_read( &tmsg );
			break;
					
		case RQC_ADI_READ:
			iret = proc_adi_read( &tmsg );
			break;

		case RQC_ADI_WRITE:
			iret = proc_adi_write( &tmsg );
			break;
		
		case RQC_IIC_CONFIG:
			iret = proc_iic_config( &tmsg );
			break;

		case RQC_SYS_DEBUG:
			iret = proc_sys_debug( &tmsg );
			break;

		default:
			iret = 1234;
			break;
		}

		if ( iret != 0 )  {

			umsg_reset_ofs( &tmsg );
			umsg_add_i32( &tmsg, iret );
			umsg_send_to_host( &tmsg );

			printf( "err : %x , %d\n", tmsg.rqc, iret );
		}
	}

	// 
	return 0;
}
